#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "interface.h"
#include "sync.h"
#include "index.h"
#include "buddy_system.h"
#include "mem_pool.h"

#define	KVS_PATH_LEN	1024
static char* g_image=NULL;

static char disk_file[KVS_PATH_LEN];
static char kvs_log[KVS_PATH_LEN];
static char mp_log[KVS_PATH_LEN];
static char buddy_log[KVS_PATH_LEN];
static char sync_log[KVS_PATH_LEN];
static char index_log[KVS_PATH_LEN];
static char bitmap_file[KVS_PATH_LEN];

static int _cal_value_size(int slot_cnt, int last_slot_info);
static int _get_slot_cnt(int value_size);
static int _get_last_slot_info(int value_size);
static void parse(char* filename, INIT_TYPE* init_type);

int kv_init(char* config_file)
{
	INIT_TYPE init_type;
	
    mp_init(mp_log);
	g_image=(char*)mp_alloc(IMAGE_K_SIZE*1024, BIGMEM);
	
    if (g_image==NULL) 
        printf ("NULL!!!!!!!!!!\n\n\n");
	
    parse(config_file, &init_type); //if some undefine ,config it.
	printf ("parse done.\n");

	sync_init(disk_file, sync_log);	
	idx_init(init_type, g_image, index_log);
	disk_init(init_type, g_image, bitmap_file, buddy_log);

	return KV_INIT_SUCCESS;
}


int kv_exit()
{
/* sync() */

	disk_exit();
	idx_exit();
	sync_exit();
	mp_free(g_image);
//	mp_exit();

	return KV_EXIT_SUCCESS;
}

int kv_get(char* key, int key_size, char* buf, int buf_size)
{
	int slot_cnt, last_slot_info, value_size;
	PTR_DISK disk_location;	
	STATE state;

	state=idx_search(key, key_size, &disk_location, &slot_cnt, &last_slot_info);
	if (state==IDX_NODE_NOT_EXIST) 
        return KV_GET_FAIL;
	
    value_size=_cal_value_size(slot_cnt, last_slot_info);
	sync_read(DISK_VALUE+disk_location, buf, value_size);
	buf[value_size]=0;
	
    return KV_GET_SUCCESS;
}


int kv_put(char* key, int key_size, char* value, int value_size)
{
	int slot_cnt, last_slot_info;
	PTR_DISK disk_location;
	STATE state;
	
	slot_cnt=_get_slot_cnt(value_size);
	last_slot_info=_get_last_slot_info(value_size);

	disk_location=disk_alloc(slot_cnt);

	state=idx_insert(key, key_size, disk_location, slot_cnt, last_slot_info);
	
    if (state==IDX_NODE_EXIST)
	{
		disk_free(disk_location);
		return KV_PUT_FAIL;
	}


	sync_write(DISK_VALUE+disk_location, value, value_size);

	return KV_PUT_SUCCESS;
}


int kv_delete(char* key, int key_size)
{
	PTR_DISK disk_location;
	STATE state;

	state=idx_delete(key, key_size, &disk_location);
    
    if (state==IDX_NODE_NOT_EXIST) 
        return KV_DELETE_FAIL;
    
	disk_free(disk_location);	
	
    return KV_DELETE_SUCCESS;
}


static int _cal_value_size(int slot_cnt, int last_slot_info)
{
	return (slot_cnt-1)*CHUNK_SIZE+last_slot_info;
}

static int _get_slot_cnt(int value_size)
{
	if (value_size%CHUNK_SIZE==0) 
        return value_size/CHUNK_SIZE;
	
    return value_size/CHUNK_SIZE+1;
}

static int _get_last_slot_info(int value_size)
{
	return value_size%CHUNK_SIZE;
}

static void parse(char* filename, INIT_TYPE* init_type)
{
	char str_type[1024], str_tmp[1024], str_value[1024];
	FILE* config_file=NULL;
	char* p;
    
    config_file=fopen(filename, "rwa");

	while ( fscanf(config_file, "%s %s %s", str_type, str_tmp, str_value) != EOF)
	{
		printf ("%s : %s\n", str_type, str_value);
		
        if ( strcmp(str_type, "init_type")==0 )
		{
			if ( strcmp(str_value, "create")==0 ) 
                *init_type=INIT_TYPE_CREATE;
			else *init_type=INIT_TYPE_LOAD;
		}
		else if ( strcmp(str_type,"disk_file")==0 )
		{
			strncpy(disk_file, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "kvs_log")==0 )
		{
			strncpy(kvs_log, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "kvs_mem_log")==0 )
		{
			strncpy(mp_log, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "kvs_disk_log")==0 )
		{
			strncpy(buddy_log, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "kvs_sync_log")==0 )
		{
			strncpy(sync_log, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "kvs_index_log")==0 )
		{
			strncpy(index_log, str_value, KVS_PATH_LEN );
		}
		else if ( strcmp(str_type, "bitmap_file")==0 )
		{
			strncpy(bitmap_file, str_value, KVS_PATH_LEN );
		}
		else printf ("parse error!\n");
	}

	fclose(config_file);
}
